use std::fmt::Display;

use crate::Validator;

pub trait ConstantEqMarker: Eq + Display {}

impl ConstantEqMarker for u8 {}
impl ConstantEqMarker for u16 {}
impl ConstantEqMarker for u32 {}
impl ConstantEqMarker for u64 {}
impl ConstantEqMarker for u128 {}
impl ConstantEqMarker for usize {}
impl ConstantEqMarker for i8 {}
impl ConstantEqMarker for i16 {}
impl ConstantEqMarker for i32 {}
impl ConstantEqMarker for i64 {}
impl ConstantEqMarker for i128 {}
impl ConstantEqMarker for isize {}
impl ConstantEqMarker for bool {}
impl ConstantEqMarker for char {}
impl ConstantEqMarker for String {}
impl ConstantEqMarker for &str {}
impl ConstantEqMarker for &String {}

pub struct ConstantValidator<T: ConstantEqMarker> {
    pub value: T,
}

impl<T: ConstantEqMarker> Validator<T> for ConstantValidator<T> {
    type Error = String;

    fn validate(
        &self,
        ident: Option<&str>,
        name: Option<&str>,
        data: &T,
    ) -> Result<(), Self::Error> {
        if !self.value.eq(data) {
            return Err(const_error(ident, name, data, &self.value));
        }
        Ok(())
    }
}

fn const_error<T: ConstantEqMarker>(
    ident: Option<&str>,
    name: Option<&str>,
    data: &T,
    expected: &T,
) -> String {
    let field = name.or(ident).unwrap_or_default();
    format!("{}期望值是: {}, 输入的是: {}", field, expected, data)
}
